package src.ORM;

import src.POJO.User;
import src.Utils.SQLPool;

import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class SqlSession {
    //使用SqlSession创建一个公用的SQL查询方法
    public static final SqlSession instance = new SqlSession();
    private Handler handler = new Handler();

    //常规写法
    public  <T> List<T> select(String sql, Object... values){
        try {
            List<T> objs = new ArrayList<>();
            Connection connection = SQLPool.getInstance().getConnection();
            PreparedStatement pst = connection.prepareStatement(sql);
            for (int i =0;i<values.length;i++){
                //jdbc会自动转换类型
                pst.setObject(i+1,values[i]);
            }
            ResultSet set = pst.executeQuery();
            while (set.next()){
                objs.add((T) new User(set.getInt(1),set.getString(2),set.getInt(3)));
            }
            pst.close();
            connection.close();
            set.close();
            return objs;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }finally {
            System.out.println("执行完毕");
        }
    }

    //通过传入重写的rowMapper来实现结果集转对象
    public <T> T selectOne(String sql,RowMapper rm,Object... values){
        T obj = null; //范型对象
        try {
            Connection connection = SQLPool.getInstance().getConnection();
            PreparedStatement pst = connection.prepareStatement(sql);
            for (int i =0;i<values.length;i++){
                //jdbc会自动转换类型
                pst.setObject(i+1,values[i]);
            }
            ResultSet set = pst.executeQuery();
            while (set.next()){
                //对执行结果进行对象封装
                obj =  rm.rowMapper(set);
            }
            set.close();
            connection.close();
            pst.close();
            return obj;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }finally {

            System.out.println("执行完毕");
        }
    }

    //通过传入对象Class即可自动将结果集转对象
    public <T> List<T> select2(String sql,Class<?> cls,Object... values){
        List<T> list = new ArrayList<>();
        T obj = null; //范型对象
        try {
            Connection connection = SQLPool.getInstance().getConnection();
            PreparedStatement pst = connection.prepareStatement(sql);
            for (int i =0;i<values.length;i++){
                //jdbc会自动转换类型
                pst.setObject(i+1,values[i]);
            }
            ResultSet set = pst.executeQuery();
            while (set.next()){
                //对执行结果进行对象封装
                obj =  handler.mapperClass(set,cls);
                list.add(obj);
            }
            set.close();
            connection.close();
            pst.close();
            return list;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }finally {
            System.out.println("执行完毕");
        }
    }

    //传入SQL参数时，通过Handler类将参数自动对SQL语句进行赋值。
    //如 select * from user where id = #{id} and name = #{name} order by id desc
    //解析为 select * from user where id = ? and name = ? order by id desc 并获得参数
    public boolean insert(String sql,Object obj) throws Exception {
        //从SQL语句中获得需要插入的参数。参数名和obj的属性相对应
        List<Object> list = handler.parseSQL(sql);
        //获取处理后的SQL语句
        Connection connection = SQLPool.getInstance().getConnection();
        PreparedStatement pst = connection.prepareStatement((String) list.get(list.size()-1));
        handler.setParams(pst,obj,list);
        try {
             pst.execute();
             return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }finally {
            connection.close();
        }
    }

    public boolean delete(String sql,Object obj) throws Exception{
        return this.insert(sql,obj);
    }

    public boolean update(String sql,Object obj) throws Exception {
        return this.insert(sql,obj);
    }

    public static SqlSession getInstance() {
        synchronized (instance){
            return instance;
        }

    }

}
